package com.jmb.apiplatform.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.jmb.apiplatform.common.LoginUserInfo;
import com.jmb.apiplatform.common.PageResult;
import com.jmb.apiplatform.cores.parser.Parser;
import com.jmb.apiplatform.exception.ValidException;
import com.jmb.apiplatform.mapper.ApiTestCaseRelyDataMapper;
import com.jmb.apiplatform.mapper.RelyDataMapper;
import com.jmb.apiplatform.pojo.*;
import com.jmb.apiplatform.service.ApiTestCaseService;
import com.jmb.apiplatform.service.ApiTestPreCaseService;
import com.jmb.apiplatform.service.RelyDataService;
import com.jmb.apiplatform.util.ValidUtil;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
* @author jinmengbo
* @description 针对表【rely_data】的数据库操作Service实现
* @createDate 2025-02-15 15:17:36
*/
@Slf4j
@Service
public class RelyDataServiceImpl implements RelyDataService{

    @Autowired
    private RelyDataMapper relyDataMapper;
    @Autowired
    private Parser parser;
    @Autowired
    private ApiTestCaseRelyDataMapper apiTestCaseRelyDataMapper;
    @Autowired
    private ApiTestCaseService apiTestCaseService;
    @Autowired
    private ApiTestPreCaseService apiTestPreCaseService;
    @Autowired
    private LoginUserInfo loginUserInfo;
    @Override
    public void saveRelyData(RelyData relyData) throws ValidException {
        RelyData rely = relyDataChecker(relyData);
        String name = rely.getName();
        // name不能在在于api_case_rely_data
        if (null!= apiTestCaseRelyDataMapper.selectRelyDataByName(name)){
            log.warn("该依赖名称已存在，relyName={}, 请重新输入",name);
            throw new ValidException("该依赖名称已存在，请重新输入");
        }
        // name不能存在于rely_data
        if (null!= relyDataMapper.selectRelyDataByName(name)){
            log.info("依赖名称已存在其他依赖，relyName={}, 请重新输入",name);
            throw new ValidException("该依赖名称已存在其他依赖，请重新输入");
        }
        Date date = new Date();
        rely.setCreatedTime(date);
        rely.setUpdateTime(date);
        relyDataMapper.insertRelyData(rely);
    }

    @Override
    public void modifyRelyData(RelyData relyData, HttpServletRequest request) throws ValidException {
        RelyData relyDataDO = relyDataChecker(relyData);
        String name = relyDataDO.getName();

        // 获取当前编辑人userId
        int userId = loginUserInfo.getUserId(request);
        Integer relyId = relyDataDO.getId();
        RelyDataVO relyDataVO = this.findRelyDataById(relyId);
        Integer type = relyDataVO.getType();
        Integer modifiable = relyDataVO.getOthersModifiable();
        Integer creatorId = relyDataVO.getCreatorId();
        if (type != 1) { // 反射方法
            if (modifiable == null || creatorId == null) {
                throw new ValidException("仅允许创建人修改");
            }
            if (creatorId != userId) {
                if (modifiable.intValue() == 1) {
                    throw new ValidException("仅允许创建人修改");
                }
                // 当前编辑人与创建人不一致时，不允许修改othersModifiable和othersDeletable字段
                relyDataVO.setOthersDeletable(null);
                relyDataVO.setOthersModifiable(null);
            }
        }

        // name不能在在于t_interface_case_rely_data
        if (null != apiTestCaseRelyDataMapper.selectRelyDataByName(name)) {
            log.warn("依赖名称已存在于接口依赖，relyName={}", name);
            throw new ValidException("依赖名称已存在于接口依赖");
        }
        // name不能在在于t_rely_data
        if (!relyDataMapper.checkName(relyDataDO).isEmpty()) {
            log.warn("依赖名称已存在于其它依赖，relyName={}", name);
            throw new ValidException("依赖名称已存在于其它依赖");
        }
        Date date = new Date();
        relyDataDO.setUpdateTime(date);
        // type 依赖类型 0固定值 1反射方法 2sql
        relyDataMapper.updateRelyData(relyDataDO);
    }

    /**
     * 查看其他依赖详情
     * @param id 编号
     * @return RelyDataVO
     */
    @Override
    public RelyDataVO findRelyDataById(Integer id) {
        return relyDataMapper.selectRelyDataById(id);
    }

    /**
     * 根据名称查询详情
     * @param name 名称
     * @return RelyDataVO
     */
    @Override
    public RelyDataVO findRelyDataByName(String name) {
        return relyDataMapper.selectRelyDataByName(name);
    }

    @Override
    public PageResult<RelyDataVO> findRelyDataList(RelyDataTO relyDataTO) {
        PageHelper.startPage(relyDataTO.getPageNum(), relyDataTO.getPageSize());
        List<RelyDataVO> list = relyDataMapper.selectRelyDataList(relyDataTO);
        Page<RelyDataVO> page = (Page<RelyDataVO>) list;
        return new PageResult<>(page.getTotal(), page.getResult());
    }

    /**
     * 删除其他依赖
     * @param id 编号
     * @throws ValidException
     */
    @Override
    public void removeRelyDataById(Integer id, HttpServletRequest request) throws ValidException {
        RelyDataVO relyDataVO = relyDataMapper.selectRelyDataById(id);
        // 获取当前删除人userId
        int userId = loginUserInfo.getUserId(request);
        Integer deletable = relyDataVO.getOthersDeletable();
        Integer creatorId = relyDataVO.getCreatorId();
        if (creatorId == null) {
            throw new ValidException("仅允许创建人删除");
        }
        if (creatorId != userId && deletable.intValue() == 1) {
            throw new ValidException("仅允许创建人删除");
        }
        // 依赖类型 0固定值 1反射方法 2sql 反射方法不允许删除
        if (relyDataVO.getType() == 1) {
            log.warn("预置方法不允许删除");
            throw new ValidException("预置方法不允许删除");
        }
        relyDataMapper.deleteRelyDataById(id);

    }
    /**
     * DO校验器 参数校验以及参数处理
     * @param relyDataDO relyDataDO
     * @return DO
     * @throws ValidException 参数校验
     */
    private RelyData relyDataChecker(RelyData relyDataDO) throws ValidException {
        String name = relyDataDO.getName();
        Integer type = relyDataDO.getType();
        String value = relyDataDO.getValue();
        // 固定值、反射方法内部数据不做校验
        if (type > 1) { //0固定值 1反射方法 2sql-select 3sql-insert 4sql-update 5sql-delete 6sql-script

            ArrayList<String> dependencyNameList = parser.extractDependencyName(value);

            for (String dependencyName : dependencyNameList) {
                // 依赖值中不能包含当前依赖名称
                if (dependencyName.equals(name)) {
                    throw new ValidException("content prohibited current dependency");
                }

                // 依赖值中不能包含SQL依赖
                RelyDataVO relyDataVO = relyDataMapper.selectRelyDataByName(dependencyName);
                if (relyDataVO != null) {
                    Integer relyType = relyDataVO.getType();
                    if (relyType.intValue() > 1) {
                        throw new ValidException("content prohibited SQL dependency");
                    }

                    ApiTestCaseRelyDataVO apiTestCaseRelyDataVO = apiTestCaseRelyDataMapper.selectRelyDataByName(dependencyName);
                    if (null != apiTestCaseRelyDataVO) {
                        // 如果是接口依赖，确保接口依赖本身的headers、params、form-data、form-data-encoded、raw、断言预期结果不包含当前依赖名称
                        Integer caseId = apiTestCaseRelyDataVO.getRelyCaseId();
                        ApiTestCaseInfoVO caseInfo = apiTestCaseService.findInterfaceCaseByCaseId(caseId);
                        String headers = caseInfo.getHeaders();
                        String params = caseInfo.getParams();
                        String formData = caseInfo.getFormData();
                        String formDataEncoded = caseInfo.getFormDataEncoded();
                        String raw = caseInfo.getRaw();
                        List<ApiTestAssertVO> asserts = caseInfo.getAsserts();
                        if (parser.extractDependencyName(headers).contains(name)) {
                            throw new ValidException("内容中的接口依赖的header不能引用当前依赖名称");
                        }
                        if (parser.extractDependencyName(params).contains(name)) {
                            throw new ValidException("内容中的接口依赖的params不能引用当前依赖名称");
                        }
                        if (parser.extractDependencyName(formData).contains(name)) {
                            throw new ValidException("内容中的接口依赖的formData不能引用当前依赖名称");
                        }
                        if (parser.extractDependencyName(formDataEncoded).contains(name)) {
                            throw new ValidException("内容中的接口依赖的formDataEncoded不能引用当前依赖名称");
                        }
                        if (parser.extractDependencyName(raw).contains(name)) {
                            throw new AbstractMethodError("内容中的接口依赖的raw不能引用当前依赖名称");
                        }
                        for (ApiTestAssertVO apiTestAssertVO : asserts) {
                            String exceptedResult = apiTestAssertVO.getExceptedResult();
                            if (parser.extractDependencyName(exceptedResult).contains(name)) {
                                throw new ValidException("内容中的接口依赖的断言预期结果不能引用当前依赖名称");
                            }
                        }
                        // 如果是接口依赖，确保接口依赖前置用例的headers、params、form-data、form-data-encoded、raw、断言预期结果不包含当前依赖名称
                        List<Integer> preCaseIdList = apiTestPreCaseService.findApiTestPreCaseById(caseId);
                        for (Integer preCaseId : preCaseIdList) {
                            ApiTestCaseInfoVO preCaseInfo = apiTestCaseService.findInterfaceCaseByCaseId(preCaseId);
                            String preHeaders = preCaseInfo.getHeaders();
                            String preParams = preCaseInfo.getParams();
                            String preFormData = preCaseInfo.getFormData();
                            String preFormDataEncoded = preCaseInfo.getFormDataEncoded();
                            String preRaw = preCaseInfo.getRaw();
                            List<ApiTestAssertVO> preCaseInfoAsserts = preCaseInfo.getAsserts();
                            if (parser.extractDependencyName(preHeaders).contains(name)) {
                                throw new ValidException("内容中的接口依赖的前置用例的header不能引用当前依赖名称");
                            }
                            if (parser.extractDependencyName(preParams).contains(name)) {
                                throw new ValidException("内容中的接口依赖的前置用例的params不能引用当前依赖名称");
                            }
                            if (parser.extractDependencyName(preFormData).contains(name)) {
                                throw new ValidException("内容中的接口依赖的前置用例的formData不能引用当前依赖名称");
                            }
                            if (parser.extractDependencyName(preFormDataEncoded).contains(name)) {
                                throw new ValidException("内容中的接口依赖的前置用例的formDataEncoded不能引用当前依赖名称");
                            }
                            if (parser.extractDependencyName(preRaw).contains(name)) {
                                throw new ValidException("内容中的接口依赖的前置用例的raw不能引用当前依赖名称");
                            }
                            for (ApiTestAssertVO interfaceAssertVO : preCaseInfoAsserts) {
                                String exceptedResult = interfaceAssertVO.getExceptedResult();
                                if (parser.extractDependencyName(exceptedResult).contains(name)) {
                                    throw new ValidException("内容中的接口依赖的前置用例的断言预期结果不能引用当前依赖名称");
                                }
                            }
                        }
                    }
                }
            }
        }
        if (type != 3) { // 非新增语句时，将enable_return 设为 null
            relyDataDO.setEnableReturn(null);
        }
        if (type != 1) {
            ValidUtil.notNUll(relyDataDO.getOthersModifiable(), "请选择是否允许其他人编辑");
            ValidUtil.notNUll(relyDataDO.getOthersDeletable(), "请选择是否允许其他人删除");
            ValidUtil.size(relyDataDO.getOthersModifiable(), 0, 1, "请选择是否允许其他人编辑");
            ValidUtil.size(relyDataDO.getOthersDeletable(), 0, 1, "请选择是否允许其他人删除");
        }
        if (type < 2) { // 0固定值 1反射方法 2sql-select 3sql-insert 4sql-update 5sql-delete 6sql-script
            relyDataDO.setAnalysisRely(null);
        } else {
            ValidUtil.notNUll(relyDataDO.getAnalysisRely(), "是否解析依赖不能为空");
        }
        // 校验参数
        Integer analysisRely = relyDataDO.getAnalysisRely();
        Integer enableReturn = relyDataDO.getEnableReturn();
        if (analysisRely != null) {
            ValidUtil.size(analysisRely, 0, 1, "参数非法");
        }
        if (enableReturn != null) {
            ValidUtil.size(enableReturn, 0, 1, "参数非法");
        }
        return relyDataDO;
    }
}




